package cn.chiship.framework.upms.biz.base.service.impl;

import cn.chiship.framework.common.constants.CommonConstants;
import cn.chiship.framework.common.pojo.vo.RedisKeyVo;
import cn.chiship.framework.upms.biz.base.service.IRedisService;
import cn.chiship.sdk.cache.service.RedisService;
import cn.chiship.sdk.core.base.BaseResult;
import cn.chiship.sdk.core.base.constants.CacheConstants;
import cn.chiship.sdk.core.util.RedisUtil;
import cn.chiship.sdk.core.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

@Service
public class IRedisServiceImpl implements IRedisService {
    @Resource
    RedisService redisService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public BaseResult monitor() {
        Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info());
        Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
        Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.dbSize());

        Map<String, Object> result = new HashMap<>(3);
        result.put("info", info);
        result.put("dbSize", dbSize);

        List<Map<String, String>> pieList = new ArrayList<>();
        commandStats.stringPropertyNames().forEach(key -> {
            Map<String, String> data = new HashMap<>(2);
            String property = commandStats.getProperty(key);
            data.put("name", StringUtil.removeStart(key, "cmdstat_"));
            data.put("value", StringUtil.substringBetween(property, "calls=", ",usec"));
            pieList.add(data);
        });
        result.put("commandStats", pieList);
        return BaseResult.ok(result);
    }

    @Override
    public BaseResult keyTrees() {
        Set sortSet = new TreeSet();
        sortSet.addAll(redisService.keys(CommonConstants.COMMON_PROJECT_NAME ));
        sortSet.addAll(redisService.keys("AUTH:API_AUTHORIZATION:"+CommonConstants.COMMON_PROJECT_NAME ));
        List<RedisKeyVo> redisKeyVos = new ArrayList<>();
        Map<String, TreeSet> map = new HashMap<>(2);
        Iterator iterator = sortSet.iterator();
        while (iterator.hasNext()) {
            String key = iterator.next().toString();
            String[] keys = key.split(":");
            if (keys.length == 1) {
                RedisKeyVo redisKeyVo = new RedisKeyVo();
                redisKeyVo.setKey(key);
                redisKeyVo.setPath(key);
                redisKeyVo.setType(redisTemplate.type(key).code().toLowerCase(Locale.ROOT));
                redisKeyVos.add(redisKeyVo);
            } else {
                String tempKey = keys[0];
                TreeSet set;
                if (map.containsKey(tempKey)) {
                    set = map.get(tempKey);
                    map.put(tempKey, set);
                } else {
                    set = new TreeSet();
                    RedisKeyVo redisKeyVo = new RedisKeyVo();
                    redisKeyVo.setKey(tempKey);
                    redisKeyVo.setPath(tempKey);
                    redisKeyVo.setChildren(new ArrayList<>());
                    redisKeyVos.add(redisKeyVo);
                }
                set.add(key.substring(key.indexOf(":") + 1));

                map.put(tempKey, set);
            }
        }

        redisKeyVos = assembleRedisKey(map, redisKeyVos);
        return BaseResult.ok(redisKeyVos);
    }

    public List<RedisKeyVo> assembleRedisKey(Map<String, TreeSet> mapParams, List<RedisKeyVo> redisKeyVosParams) {
        for (Map.Entry<String, TreeSet> entry : mapParams.entrySet()) {
            for (RedisKeyVo keyVo : redisKeyVosParams) {
                if (keyVo.getKey().equals(entry.getKey()) && keyVo.getChildren() != null) {
                    TreeSet sortSet = entry.getValue();
                    List<RedisKeyVo> redisKeyVos = new ArrayList<>();
                    Map<String, TreeSet> map = new HashMap<>(2);
                    Iterator iterator = sortSet.iterator();
                    while (iterator.hasNext()) {
                        String key = iterator.next().toString();
                        String[] keys = key.split(":");
                        if (keys.length == 1) {
                            RedisKeyVo redisKeyVo = new RedisKeyVo();
                            redisKeyVo.setKey(key);
                            redisKeyVo.setPath(keyVo.getPath() + ":" + key);
                            redisKeyVo.setType(redisTemplate.type(redisKeyVo.getPath()).code().toLowerCase(Locale.ROOT));

                            List<RedisKeyVo> keyVos = keyVo.getChildren();
                            keyVos.add(redisKeyVo);
                            keyVo.setChildren(keyVos);
                        } else {
                            String tempKey = keys[0];
                            TreeSet set;
                            if (map.containsKey(tempKey)) {
                                set = map.get(tempKey);
                                map.put(tempKey, set);
                            } else {
                                set = new TreeSet();
                                RedisKeyVo redisKeyVo = new RedisKeyVo();
                                redisKeyVo.setKey(keys[0]);
                                redisKeyVo.setPath(keyVo.getPath() + ":" + keys[0]);
                                redisKeyVo.setChildren(new ArrayList<>());
                                List<RedisKeyVo> keyVos = keyVo.getChildren();
                                keyVos.add(redisKeyVo);
                                keyVo.setChildren(keyVos);
                                redisKeyVos.add(redisKeyVo);
                            }
                            set.add(key.substring(key.indexOf(":") + 1));
                            map.put(tempKey, set);
                        }
                    }
                    assembleRedisKey(map, redisKeyVos);
                }
            }
        }
        return redisKeyVosParams;
    }

    @Override
    public BaseResult value(String key) {
        DataType dataType=redisTemplate.type(key);
        if (DataType.STRING.equals(dataType)){
            return BaseResult.ok(redisService.get(key));
        }
        if (DataType.LIST.equals(dataType)){
            return BaseResult.ok(redisService.get(key));
        }
        if (DataType.HASH.equals(dataType)){
            return BaseResult.ok(redisService.hget(key));
        }
        if (DataType.SET.equals(dataType)){
            return BaseResult.ok(redisService.sGet(key));
        }
        if (DataType.ZSET.equals(dataType)){
            return BaseResult.ok(redisService.sGet(key));
        }
        return BaseResult.ok(null);
    }
}
